package protocol.data;

import protocol.Frame;
import general.Bit;

import java.util.zip.CRC32;

public class DataPacket implements Frame {
	
	private int sequenceNumber;
	private long crc;
	private int dataLength;
	private byte[] data;
	
	public int getSequenceNumber() {
		return this.sequenceNumber;
	}
	
	public void setSequenceNumber(int sequenceNumber) {
		this.sequenceNumber = sequenceNumber;
	}
	
	public long getCrc() {
		return this.crc;
	}
	
	private void setCrc(long crc) {
		this.crc = crc;
	}
	
	public int getDataLength() {
		return this.dataLength;
	}
	
	public void setDataLength(int dataLength) {
		this.dataLength = dataLength;
	}
	
	public byte[] getData() {
		return this.data;
	}
	
	public void setData(byte[] data, boolean calculateCRC) {
		if (data.length > 1437) {
			/**
			 * Too big byte array
			 */
		} else {
			this.data = data;
			/**
			 * Calculate CRC check value for the data
			 */
			if (calculateCRC) {
				CRC32 crc = new CRC32();
				crc.update(data);
				this.setCrc(crc.getValue());
			}
			/**
			 * Set the data length
			 */
			//this.setDataLength(data.length);
		}
	}
	
	/**
	 * Constructor
	 */
	public DataPacket() {
	}
	
	/**
	 * Constructor
	 * @param bytes Supplied for the method parse()
	 */
	public DataPacket(byte[] bytes) {
		this.parse(bytes);
	}
	
	public byte[] build() {
		byte[] data = new byte[1451];
		/**
		 * Set the sequence number to the packet
		 */
		System.arraycopy(
			Bit.toByteArray(this.getSequenceNumber()), 0, // source
			data, 0, // destination
			4); // copy length
		/**
		 * Set the CRC code to the packet
		 */
		System.arraycopy(
			Bit.toByteArray(this.getCrc()), 0, // source
			data, 4, // destination
			8); // copy length8
		/**
		 * Set the data length to the packet
		 */
		System.arraycopy(
			Bit.toByteArray(this.getDataLength()), 2, // source
			data, 12, // destination
			2); // copy length
		/**
		 * Set the actual data
		 */
		System.arraycopy(
			this.getData(), 0, // source
			data, 14, // destination
			this.getData().length); // copy length
		return data;
	}
	
	public void parse(byte[] bytes) {
		/**
		 * Save the sequence number
		 */
		byte[] sequenceNumber = new byte[4];
		System.arraycopy(
			bytes, 0, // source
			sequenceNumber, 0, // destination
			4); // copy length
		this.setSequenceNumber(Bit.toInt(sequenceNumber));
		/**
		 * Save the CRC code
		 */
		byte[] crc = new byte[8];
		System.arraycopy(
			bytes, 4, // source
			crc, 0,  // destination
			8); // copy length
		this.setCrc(Bit.toLong(crc));
		/**
		 * Save the data length
		 * Bit.toInt() requires 4-byte array for transformation. 
		 * Protocol uses only 2 bytes for data length
		 */
		byte[] dataLength = new byte[4]; 
		System.arraycopy(
			bytes, 12, // source
			dataLength, 2, // destination
			2); // copy length
		this.setDataLength(Bit.toInt(dataLength));
		/**
		 * Save the actual data
		 */
		byte[] data = new byte[1437];
		System.arraycopy(
			bytes, 14, // source
			data, 0,  // destination
			1437); // copy length
		this.setData(data, false);
	}
	
}